package com.minivision.fdiot.util;

import java.io.BufferedOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.ByteBuffer;
import java.security.MessageDigest;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import java.util.Map.Entry;

import org.apache.commons.lang3.StringUtils;

import com.minivision.fdiot.redis.RedisIdGenerator;

/**
 * 人脸特征值转换工具类
 * @author hughzhao
 * @2018年3月1日
 */
public class FeatureUtils {
  
  /**
   * 人脸特征值float数组转换为Base64字符串
   * @param feature
   * @return
   */
  public static String encode(float[] feature) {
    if(feature == null){
      return null;
    }
    ByteBuffer buffer = ByteBuffer.allocate(feature.length * 4);
    for(float f: feature){
      buffer.putFloat(f);
    }
    return Base64.getEncoder().encodeToString(buffer.array());
  }
  
  /**
   * 人脸特征值Base64字符串还原为float数组
   * @param feature
   * @return
   */
  public static float[] decode(String feature) {
    if(StringUtils.isEmpty(feature)){
      return null;
    }
    byte[] bytes = Base64.getDecoder().decode(feature);
    ByteBuffer buffer = ByteBuffer.wrap(bytes);
    int size = bytes.length / 4;
    
    float[] fs = new float[size];
    for(int i=0;i<size;i++){
      fs[i] = buffer.getFloat();
    }
    return fs;
  }
  
  /**
   * 人脸库人脸特征值写入输出流
   * @param features
   * @param os
   * @throws IOException
   */
  public static void encodeFaceSet(Map<String, float[]> features, OutputStream os) throws IOException{
      DataOutputStream dos = new DataOutputStream(new BufferedOutputStream(os));
      int count = features.size();
      int featureSize = features.values().stream().findAny().orElse(new float[0]).length;
      dos.writeInt(count);
      dos.writeInt(featureSize);
      if(count > 0){
        for(Entry<String, float[]> e: features.entrySet()){
          byte[] keyBytes = RedisIdGenerator.asBytes(UUID.fromString(e.getKey()));
          dos.write(keyBytes);
          float[] value = e.getValue();
          for(float f: value){
            dos.writeFloat(f);
          }
          dos.flush();
        }
      }
      dos.flush();
  }
  
  /**
   * 从输入流中读取人脸库人脸特征值
   * @param is
   * @return
   * @throws IOException
   */
  public static Map<String, float[]> decodeFaceSet(InputStream is) throws IOException{
    DataInputStream dis = new DataInputStream(is);
    Map<String, float[]> features = new HashMap<>();
    int count = dis.readInt();
    if(count == 0){
      return features;
    }
    int featureLenth = dis.readInt();
    byte[] keyBytes = new byte[16];
    
    for(int i=0;i<count; i++){
      dis.readFully(keyBytes);
      for(int k = 0 ; k < keyBytes.length; k ++){
        System.out.println(keyBytes[k]);
      }
      UUID uuid = RedisIdGenerator.asUuid(keyBytes);
      String key = uuid.toString();
      float[] feature = new float[featureLenth];
      for(int j = 0; j<featureLenth; j++){
        feature[j] = dis.readFloat();
      }
      features.put(key, feature);
    }
    return features;
  }

  public static String MD5(String s){
    try {
      MessageDigest md = MessageDigest.getInstance("MD5");
      byte[] bytes = md.digest(s.getBytes("utf-8"));
      return toHex(bytes);
    }
    catch (Exception e) {
      throw new RuntimeException(e);
    }
  }

  public static String toHex(byte[] bytes) {

    final char[] HEX_DIGITS = "0123456789ABCDEF".toCharArray();
    StringBuilder ret = new StringBuilder(bytes.length * 2);
    for (int i=0; i<bytes.length; i++) {
      ret.append(HEX_DIGITS[(bytes[i] >> 4) & 0x0f]);
      ret.append(HEX_DIGITS[bytes[i] & 0x0f]);
    }
    return ret.toString();
  }
}
